/******************************/
/* 描述：将json或split(格式同json)或lcdat文件重写到excel中 */
/* 所以尽量不要将前端的配置文件分离
/* 作者：by 杉木说 */
/* 日期：2023-05-16 */
/******************************/

const Utils = require("./Utils");
const fs = require('fs');
const path = require('path');
const zlib = require('zlib');
const xlsx = require('node-xlsx');

// 指定目录和文件名,输出目录
let directoryPath, outputDir;
// lcdat/split文件的解密密钥
let decryptCode;

/** 遍历目录 */
function traverseDirectorySync(targetDirectoryPath) {
  const files = fs.readdirSync(targetDirectoryPath);
  files.forEach(file => {
    const filePath = path.join(targetDirectoryPath, file);
    if (fs.statSync(filePath).isDirectory()) {
      traverseDirectorySync(filePath); // 递归遍历子目录
    } else {
      // const fileExtension = path.extname(file);
      if (file.endsWith(".json")) {
        let json = JSON.parse(fs.readFileSync(filePath, "utf-8"));
        handleJsonSheet(filePath, json, 0);
      } else if (file.endsWith(".split.bytes")) {
        handleReadFileStream(filePath, true);
      } else if (file.endsWith(".lcdat.bytes")) {
        handleReadFileStream(filePath, false);
      }
    }
  });
}

/** 读取数据方法 */
function handleReadFileStream(fileReadPath, split = false) {
  // 创建读取流
  const readStream = fs.createReadStream(fileReadPath);
  // 创建解压缩器
  const gunzip = zlib.createGunzip();
  // 读取流通过解压缩器进行解压缩
  readStream.pipe(gunzip);
  // 用一个缓冲区来存储解压缩后的数据
  let buffer = Buffer.from('');
  gunzip.on('data', (data) => { buffer = Buffer.concat([buffer, data]); });
  gunzip.on('end', () => {
    let jsonStr = "";
    try {
      jsonStr = JSON.parse(Utils.XORDecrypt(buffer.toString(), decryptCode))
    } catch (error) {
      console.log("!!! 错误: 读取后Json解析失败!请检查加密解密的密钥是否一致!");
      console.log("!!! 错误: 文件地址!", fileReadPath);
      return;
    }

    if (split) {
      handleJsonSheet(fileReadPath, jsonStr, 1);
    } else {
      let countTemp = 0;
      for (const key in jsonStr) {
        countTemp++;
        const singleJsonData = jsonStr[key];
        handleJsonSheet(fileReadPath, singleJsonData, 2, countTemp);
      }
    }
  });
}

/** 处理Json数据 */
function handleJsonSheet(filePath, jsonData, type, lcdatIndex) {
  let titleArr = getSheetColumnTitle(jsonData);
  if (titleArr == null) {
    console.log(`温馨提示: 文件未转存成功 => ${filePath}`);
    return;
  }

  // 拿到每一行的数据,并填充到excel表中
  let fieldTypeArr = getSheetColumnFieldType(jsonData);
  let allRow = [titleArr, ["这一行是用来填写字段提示信息的,下面一行是填写字段类型和输出类型的,请修改!"], fieldTypeArr];
  let length = jsonData.length;
  for (let index = 1; index < length; index++) {
    const rowData = jsonData[index];
    const rowArray = [];
    for (const key in rowData) {
      rowArray.push(rowData[key]);
    }
    allRow.push(rowArray)
  }

  // 创建 Excel 表格
  const buffer = xlsx.build([{ name: 'Sheet', data: allRow }]);

  // 文件名
  let filename = path.basename(filePath) + ".xlsx";
  if (type == 2) {
    filename = path.basename(filePath) + "_" + lcdatIndex + ".xlsx";
  }

  let dirname = path.join(outputDir, filename);
  Utils.checkAndMkDir(path.dirname(dirname))
  // 保存为 Excel 文件
  fs.writeFileSync(dirname, buffer, { flag: 'w' });
  console.log("温馨提示:", filename + ' - Excel 文件已转存成功! FilePath:'+filePath);
}

/** 
 * 获取Excel表的所有标题列,Josn对象必须是List<Object>
 */
function getSheetColumnTitle(data) {
  if (!Array.isArray(data)) return null;
  if (data.length <= 0) return null;
  let arr = [];
  for (const key in data[0]) {
    const element = key;
    arr.push(element);
  }
  return arr;
}

/** 
 * 获取Excel表的所有列字段类型,Josn对象必须是List<Object>
 * 这里随便写写就行...
 */
function getSheetColumnFieldType(data) {
  if (!Array.isArray(data)) return null;
  if (data.length <= 0) return null;
  let arr = [];
  for (const key in data[0]) {
    let type = "type";
    arr.push(type + "#all");
  }
  return arr;
}

/**
获取工具的配置文件
*/
function getToolConfig() {
  let cfgJson = Utils.getToolConfigs();
  decryptCode = cfgJson.RestoreToExcel.DecryptCode;
  directoryPath = cfgJson.RestoreToExcel.ReadFilePath;
  outputDir = path.join(directoryPath, "Output-excel");
}

/**
 * 执行
 */
function start() {
  getToolConfig();
  traverseDirectorySync(directoryPath);
}

start();